/* 
 * File:   ICM.h
 * Author: hadrien
 *
 * Created on 16 avril 2012, 16:03
 */

#ifndef ICM_H
#define	ICM_H
#include <cstdlib>
#include "GaussianProcess.h"
#include <math.h>
#include <stdio.h>
#include <iostream>

template<typename IMAGEPARAMETERS, typename ENERGYCALCULATOR, typename ICMPARAMETERS>
class ICM {
public:

    typedef IMAGEPARAMETERS Params;
    typedef typename Params::features_vector_t features_vector_t;
    typedef typename Params::label_t label_t;
    typedef ENERGYCALCULATOR energy_t;
    typedef ICMPARAMETERS ICMParams;
    typedef GaussianProcess<Params> model_t;

    void operator()(const model_t& model, features_vector_t const * const *observations, label_t** labels, const bool& init = true) {
        int i, j;
        double summa_deltaE, E;
        label_t r;

        energy_t energy(&model, observations);
        
        //Init label to the ML if it's null
        if(init){
            for (int i = 0; i < Params::getHeight(); ++i) {
                for (int j = 0; j < Params::getWidth(); ++j) {
                    labels[i][j] = energy.getMaximumLikelyhood(i, j);
                }
            }
        }

        double E_old = energy.globalEnergy(labels);

        do {
            summa_deltaE = 0.0;
            for (i = 0; i < Params::getHeight(); ++i)
                for (j = 0; j < Params::getWidth(); ++j) {
                    for (r = 0; r < Params::getL(); ++r) {
                        if (energy.localEnergy(i, j, labels[i][j], labels) > energy.localEnergy(i, j, r, labels)) {
                            labels[i][j] = r;
                        }
                    }
                }
            E = energy.globalEnergy(labels);
            summa_deltaE += fabs(E_old - E);
            E_old = E;
            printf("\nEnergy: %f\n", E);
        } while (summa_deltaE > ICMParams::getStopCriterion()); // stop when energy change is small
    }
private:

};

#endif	/* ICM_H */

